#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
SQL编辑器组件模块 - 优化版本
提供SQL编辑和执行功能，参考主流SQL编辑器设计
优化内容：
1. 性能优化：减少不必要的重绘和计算
2. 用户体验：改进快捷键、自动保存、智能缩进
3. 功能增强：代码折叠、多光标编辑、智能括号匹配
4. 错误处理：更好的错误提示和恢复机制
"""

import logging
from typing import Dict, List, Any, Optional, Tuple
import uuid
import re
import time
import threading
from functools import lru_cache

from PySide6.QtCore import Qt, Signal, Slot, QTimer, QSize, QRect, QEvent, QThread, QObject
from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, 
                              QPlainTextEdit, QPushButton, QTabWidget,
                              QToolBar, QToolButton, QSplitter,
                              QLabel, QProgressBar, QMessageBox,
                              QScrollBar, QFrame, QMenu, QTextEdit,
                              QApplication, QCheckBox)
from PySide6.QtGui import (QFont, QFontMetrics, QTextCursor, QKeyEvent, QAction,
                          QPainter, QColor, QTextFormat, QTextCharFormat,
                          QSyntaxHighlighter, QTextBlockUserData, QIcon, QTextOption,
                          QCursor, QKeySequence, QTextBlock, QPalette, QShortcut)

from ui.widgets.sql_highlighter import SQLHighlighter, SQLErrorHighlighter, SQLBlockData
from ui.widgets.completion import SQLCompleter
from core.query_manager import get_query_manager, QueryResult
from ui.style_manager import get_icon, get_style_manager
from config.settings import settings
from core.i18n import tr


# 初始化日志记录器
logger = logging.getLogger("sql_editor")


class LineNumberArea(QWidget):
    """行号显示区域 - 优化版本"""
    
    def __init__(self, editor):
        """初始化行号区域
        
        Args:
            editor: 代码编辑器实例
        """
        super().__init__(editor)
        self.code_editor = editor
        self._cached_line_count = 0
        self._cached_width = 0
        
    def sizeHint(self):
        """返回建议大小"""
        return QSize(self.code_editor.lineNumberAreaWidth(), 0)
        
    def paintEvent(self, event):
        """绘制行号"""
        self.code_editor.lineNumberAreaPaintEvent(event)
        
    def mousePressEvent(self, event):
        """鼠标点击事件 - 支持行选择"""
        if event.button() == Qt.LeftButton:
            # 计算点击的行号
            line_height = self.code_editor.fontMetrics().height()
            line_number = event.pos().y() // line_height
            
            # 选择整行
            cursor = self.code_editor.textCursor()
            cursor.movePosition(QTextCursor.Start)
            cursor.movePosition(QTextCursor.Down, QTextCursor.MoveAnchor, line_number)
            cursor.select(QTextCursor.LineUnderCursor)
            self.code_editor.setTextCursor(cursor)


class SQLCodeEditor(QPlainTextEdit):
    """代码编辑器组件 - 优化版本"""
    
    # 新增信号
    bracket_matched = Signal(int, int)  # 括号匹配信号
    auto_save_triggered = Signal()      # 自动保存信号
    
    def __init__(self, parent=None):
        """初始化代码编辑器"""
        super().__init__(parent)
        
        # 性能优化标志
        self._updating = False
        self._last_update_time = 0
        self._update_delay = 50  # 50ms延迟更新
        
        # 设置行高
        self.setLineWrapMode(QPlainTextEdit.NoWrap)
        
        # 创建行号区域
        self.line_number_area = LineNumberArea(self)
        
        # 添加语法高亮器
        self.highlighter = SQLHighlighter(self.document())
        
        # 自动保存定时器
        self.auto_save_timer = QTimer()
        self.auto_save_timer.setSingleShot(True)
        self.auto_save_timer.timeout.connect(self.auto_save_triggered.emit)
        
        # 语法检查定时器
        self.syntax_check_timer = QTimer()
        self.syntax_check_timer.setSingleShot(True)
        self.syntax_check_timer.timeout.connect(self._check_sql_syntax)
        
        # 括号匹配
        self.bracket_pairs = {'(': ')', '[': ']', '{': '}', "'": "'", '"': '"'}
        self.bracket_positions = []
        
        # 多光标支持
        self.extra_cursors = []
        
        # 连接信号
        self.blockCountChanged.connect(self.updateLineNumberAreaWidth)
        self.updateRequest.connect(self.updateLineNumberArea)
        self.cursorPositionChanged.connect(self._on_cursor_position_changed)
        self.textChanged.connect(self._on_text_changed)
        
        # 设置样式（在字体设置之前）
        self.update_styles()
        
        # 自动缩进功能
        self.setAutoIndentation(True)
        
        # 折叠状态
        self.code_folding = {}  # 行号 -> 是否折叠
        
        # 确保行尾字符一致（跨平台兼容）
        self.document().setDefaultTextOption(QTextOption())
        
        # 智能缩进设置
        self.indent_size = 4
        self.use_spaces = True
        
        # 自动补全括号
        self.auto_close_brackets = True
        
        # 从设置中读取字体配置（在最后设置字体，确保不被覆盖）
        editor_font_family = settings.get("editor_font_family", "Consolas")
        editor_font_size = settings.get("editor_font_size", 12)
        
        # 设置字体（最后执行，确保生效）
        self.set_editor_font(editor_font_family)
        self.set_font_size(editor_font_size)
        
        # 初始化行号区域宽度
        self.updateLineNumberAreaWidth(0)
        
        # 高亮当前行
        self.highlightCurrentLine()
        
        # 设置制表符宽度
        self.update_tab_width()

        
    def _on_cursor_position_changed(self):
        """光标位置改变时的处理 - 优化版本"""
        if self._updating:
            return
            
        current_time = time.time() * 1000
        if current_time - self._last_update_time < self._update_delay:
            return
            
        self._last_update_time = current_time
        
        # 高亮当前行
        self.highlightCurrentLine()
        
        # 括号匹配
        self._highlight_matching_brackets()
        
    def _on_text_changed(self):
        """文本改变时的处理"""
        if self._updating:
            return
            
        # 启动自动保存定时器
        if settings.get("auto_save_queries", True):
            self.auto_save_timer.start(2000)  # 2秒后自动保存
            
        # 启动语法检查定时器
        self.syntax_check_timer.start(1000)  # 1秒后检查语法
            
    def _highlight_matching_brackets(self):
        """高亮匹配的括号"""
        cursor = self.textCursor()
        position = cursor.position()
        
        # 清除之前的括号高亮
        self.bracket_positions.clear()
        
        # 检查当前位置和前一个位置的字符
        text = self.toPlainText()
        if position > 0 and position <= len(text):
            char_before = text[position - 1] if position > 0 else ''
            char_at = text[position] if position < len(text) else ''
            
            # 查找匹配的括号
            match_pos = -1
            if char_before in self.bracket_pairs:
                match_pos = self._find_matching_bracket(position - 1, char_before, True)
            elif char_at in self.bracket_pairs.values():
                # 反向查找开括号
                for open_bracket, close_bracket in self.bracket_pairs.items():
                    if char_at == close_bracket:
                        match_pos = self._find_matching_bracket(position, char_at, False)
                        break
                        
            if match_pos != -1:
                self.bracket_positions = [position - 1 if char_before in self.bracket_pairs else position, match_pos]
                self.bracket_matched.emit(self.bracket_positions[0], self.bracket_positions[1])
                
        # 更新显示
        self.update()
        
    def _find_matching_bracket(self, start_pos: int, bracket: str, forward: bool) -> int:
        """查找匹配的括号位置"""
        text = self.toPlainText()
        if forward:
            target = self.bracket_pairs.get(bracket)
            if not target:
                return -1
                
            count = 1
            for i in range(start_pos + 1, len(text)):
                if text[i] == bracket:
                    count += 1
                elif text[i] == target:
                    count -= 1
                    if count == 0:
                        return i
        else:
            # 反向查找
            for open_bracket, close_bracket in self.bracket_pairs.items():
                if bracket == close_bracket:
                    count = 1
                    for i in range(start_pos - 1, -1, -1):
                        if text[i] == bracket:
                            count += 1
                        elif text[i] == open_bracket:
                            count -= 1
                            if count == 0:
                                return i
                    break
                    
        return -1
        
    def keyPressEvent(self, event):
        """按键事件处理 - 增强版本"""
        # 首先检查是否有补全器需要处理这个事件
        # 通过父级SQLEditorTab查找补全器
        parent_tab = self.parent()
        while parent_tab and not hasattr(parent_tab, 'completer'):
            parent_tab = parent_tab.parent()
            
        if (parent_tab and hasattr(parent_tab, 'completer') and 
            parent_tab.completer and 
            hasattr(parent_tab.completer, 'popup') and 
            parent_tab.completer.popup.isVisible()):
            # 如果补全窗口可见，让补全器优先处理键盘事件
            if parent_tab.completer.handle_key_press(event):
                return
        
        # 处理自动补全括号
        if self.auto_close_brackets and event.text() in self.bracket_pairs:
            cursor = self.textCursor()
            cursor.insertText(event.text() + self.bracket_pairs[event.text()])
            cursor.movePosition(QTextCursor.Left)
            self.setTextCursor(cursor)
            return
            
        # 处理智能缩进
        if event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter:
            self._handle_smart_indent()
            return
            
        # 处理Tab键
        if event.key() == Qt.Key_Tab:
            if event.modifiers() == Qt.ShiftModifier:
                self._unindent_selection()
            else:
                self._indent_selection()
            return
            
        # 处理多行注释快捷键
        if event.key() == Qt.Key_Slash and event.modifiers() == (Qt.ControlModifier | Qt.ShiftModifier):
            self._toggle_block_comment()
            return
            
        # 处理重复行快捷键
        if event.key() == Qt.Key_D and event.modifiers() == Qt.ControlModifier:
            self._duplicate_line()
            return
            
        # 处理删除行快捷键
        if event.key() == Qt.Key_K and event.modifiers() == (Qt.ControlModifier | Qt.ShiftModifier):
            self._delete_line()
            return
            
        # 处理移动行快捷键
        if event.key() == Qt.Key_Up and event.modifiers() == (Qt.AltModifier):
            self._move_line_up()
            return
        elif event.key() == Qt.Key_Down and event.modifiers() == (Qt.AltModifier):
            self._move_line_down()
            return
            
        # 默认处理
        super().keyPressEvent(event)
        
    def _handle_smart_indent(self):
        """智能缩进处理"""
        cursor = self.textCursor()
        current_block = cursor.block()
        current_text = current_block.text()
        
        # 计算当前行的缩进
        indent = 0
        for char in current_text:
            if char == ' ':
                indent += 1
            elif char == '\t':
                indent += self.indent_size
            else:
                break
                
        # 检查是否需要增加缩进
        stripped_text = current_text.strip().upper()
        if (stripped_text.endswith('(') or 
            stripped_text.startswith(('SELECT', 'FROM', 'WHERE', 'JOIN', 'CASE', 'WHEN'))):
            indent += self.indent_size
            
        # 插入新行和缩进
        cursor.insertText('\n' + ' ' * indent)
        
    def _indent_selection(self):
        """缩进选中文本"""
        cursor = self.textCursor()
        if cursor.hasSelection():
            # 多行缩进
            start = cursor.selectionStart()
            end = cursor.selectionEnd()
            
            cursor.setPosition(start)
            start_block = cursor.block()
            
            cursor.setPosition(end)
            end_block = cursor.block()
            
            cursor.beginEditBlock()
            
            current_block = start_block
            while current_block.isValid() and current_block.blockNumber() <= end_block.blockNumber():
                cursor.setPosition(current_block.position())
                if self.use_spaces:
                    cursor.insertText(' ' * self.indent_size)
                else:
                    cursor.insertText('\t')
                current_block = current_block.next()
                
            cursor.endEditBlock()
        else:
            # 单行缩进
            if self.use_spaces:
                cursor.insertText(' ' * self.indent_size)
            else:
                cursor.insertText('\t')
                
    def _unindent_selection(self):
        """取消缩进选中文本"""
        cursor = self.textCursor()
        if cursor.hasSelection():
            # 多行取消缩进
            start = cursor.selectionStart()
            end = cursor.selectionEnd()
            
            cursor.setPosition(start)
            start_block = cursor.block()
            
            cursor.setPosition(end)
            end_block = cursor.block()
            
            cursor.beginEditBlock()
            
            current_block = start_block
            while current_block.isValid() and current_block.blockNumber() <= end_block.blockNumber():
                text = current_block.text()
                if text.startswith(' ' * self.indent_size):
                    cursor.setPosition(current_block.position())
                    cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, self.indent_size)
                    cursor.removeSelectedText()
                elif text.startswith('\t'):
                    cursor.setPosition(current_block.position())
                    cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, 1)
                    cursor.removeSelectedText()
                current_block = current_block.next()
                
            cursor.endEditBlock()
        else:
            # 单行取消缩进
            cursor = self.textCursor()
            cursor.movePosition(QTextCursor.StartOfLine)
            text = cursor.block().text()
            if text.startswith(' ' * self.indent_size):
                cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, self.indent_size)
                cursor.removeSelectedText()
            elif text.startswith('\t'):
                cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, 1)
                cursor.removeSelectedText()
                
    def _toggle_block_comment(self):
        """切换块注释"""
        cursor = self.textCursor()
        if cursor.hasSelection():
            selected_text = cursor.selectedText()
            if selected_text.startswith('/*') and selected_text.endswith('*/'):
                # 移除注释
                new_text = selected_text[2:-2]
                cursor.insertText(new_text)
            else:
                # 添加注释
                cursor.insertText('/*' + selected_text + '*/')
                
    def _duplicate_line(self):
        """复制当前行"""
        cursor = self.textCursor()
        cursor.select(QTextCursor.LineUnderCursor)
        selected_text = cursor.selectedText()
        cursor.movePosition(QTextCursor.EndOfLine)
        cursor.insertText('\n' + selected_text)
        
    def _delete_line(self):
        """删除当前行"""
        cursor = self.textCursor()
        cursor.select(QTextCursor.LineUnderCursor)
        cursor.removeSelectedText()
        cursor.deleteChar()  # 删除换行符
        
    def _move_line_up(self):
        """向上移动当前行"""
        cursor = self.textCursor()
        current_block = cursor.block()
        if current_block.blockNumber() == 0:
            return
            
        cursor.beginEditBlock()
        
        # 选择当前行
        cursor.select(QTextCursor.LineUnderCursor)
        current_text = cursor.selectedText()
        cursor.removeSelectedText()
        cursor.deleteChar()  # 删除换行符
        
        # 移动到上一行开始
        cursor.movePosition(QTextCursor.Up)
        cursor.movePosition(QTextCursor.StartOfLine)
        cursor.insertText(current_text + '\n')
        
        cursor.endEditBlock()
        
    def _move_line_down(self):
        """向下移动当前行"""
        cursor = self.textCursor()
        current_block = cursor.block()
        if current_block.next().isValid() == False:
            return
            
        cursor.beginEditBlock()
        
        # 选择当前行
        cursor.select(QTextCursor.LineUnderCursor)
        current_text = cursor.selectedText()
        cursor.removeSelectedText()
        cursor.deleteChar()  # 删除换行符
        
        # 移动到下一行结束
        cursor.movePosition(QTextCursor.Down)
        cursor.movePosition(QTextCursor.EndOfLine)
        cursor.insertText('\n' + current_text)
        
        cursor.endEditBlock()

    def set_editor_font(self, font_family):
        """设置编辑器字体
        
        Args:
            font_family: 字体族名
        """
        logger.info(f"设置字体族: {font_family}")
        
        # 获取当前字体大小
        current_size = self.font().pointSize()
        if current_size <= 0:
            current_size = 12  # 默认大小
            
        logger.info(f"当前字体大小: {current_size}")
            
        font = QFont(font_family)
        font.setFixedPitch(True)
        font.setPointSize(current_size)  # 保持当前字体大小
        
        logger.info(f"创建的新字体: {font.family()}, 大小: {font.pointSize()}")
        
        self.setFont(font)
        
        # 验证字体是否设置成功
        actual_font = self.font()
        logger.info(f"设置后的实际字体: {actual_font.family()}, 大小: {actual_font.pointSize()}")
        
        # 同时更新行号区域的字体
        if hasattr(self, 'line_number_area'):
            line_number_font = QFont(font_family)
            line_number_font.setPointSize(current_size)
            self.line_number_area.setFont(line_number_font)
            
        self.update_tab_width()
        
        # 强制更新显示
        self.updateLineNumberAreaWidth(0)
        if hasattr(self, 'line_number_area'):
            self.line_number_area.update()
        self.update()
        
    def set_font_size(self, size):
        """设置字体大小
        
        Args:
            size: 字体大小
        """
        logger.info(f"设置字体大小: {size}")
        
        # 验证字体大小的有效性
        if size <= 0 or size > 72:
            logger.warning(f"无效的字体大小: {size}，使用默认值12")
            size = 12
            
        current_font = self.font()
        logger.info(f"当前字体: {current_font.family()}, 大小: {current_font.pointSize()}")
        
        font = self.font()
        font.setPointSize(size)
        
        logger.info(f"设置大小后的字体: {font.family()}, 大小: {font.pointSize()}")
        
        self.setFont(font)
        
        # 验证字体是否设置成功
        actual_font = self.font()
        logger.info(f"设置后的实际字体: {actual_font.family()}, 大小: {actual_font.pointSize()}")
        
        # 同时更新行号区域的字体大小
        if hasattr(self, 'line_number_area'):
            line_number_font = self.line_number_area.font()
            line_number_font.setPointSize(size)
            self.line_number_area.setFont(line_number_font)
        
        self.update_tab_width()
        
        # 更新行号区域宽度和布局
        self.updateLineNumberAreaWidth(0)
        if hasattr(self, 'line_number_area'):
            self.line_number_area.update()
    
    def update_tab_width(self):
        """更新制表符宽度"""
        metrics = QFontMetrics(self.font())
        self.setTabStopDistance(4 * metrics.horizontalAdvance(' '))
    
    def update_styles(self):
        """更新编辑器样式 - 使用QSS样式"""
        # 从设置中读取字体配置
        editor_font_family = settings.get("editor_font_family", "Consolas")
        editor_font_size = settings.get("editor_font_size", 12)
        
        # 移除内联样式，让QSS样式表接管
        self.setStyleSheet("")
        
        # 设置字体（这不影响QSS样式）
        font = QFont(editor_font_family, editor_font_size)
        self.setFont(font)
        
        # 更新行号区域字体
        if hasattr(self, 'line_number_area'):
            # 移除内联样式，设置对象名以便QSS匹配
            self.line_number_area.setObjectName("line_number_area")
            self.line_number_area.setStyleSheet("")
            self.line_number_area.setFont(font)
        
        # 重绘编辑器
        self.repaint()
    
    def wheelEvent(self, event):
        """处理滚轮事件 - 支持Ctrl+滚轮缩放"""
        if self._check_wheel_zoom(event):
            return
        super().wheelEvent(event)
        
    def _check_wheel_zoom(self, event):
        """检查滚轮缩放操作"""
        # 检查是否启用了滚轮缩放功能
        if not settings.get("enable_editor_wheel_zoom", True):
            logger.info("滚轮缩放功能被禁用")
            return False
            
        if event.modifiers() == Qt.ControlModifier:
            delta = event.angleDelta().y()
            logger.info(f"执行滚轮缩放: delta={delta}")
            if delta > 0:
                self.zoom_in()
            elif delta < 0:
                self.zoom_out()
            event.accept()
            return True
        return False
    
    def zoom_in(self):
        """放大字体"""
        font = self.font()
        size = font.pointSize()
        logger.info(f"zoom_in: 当前字体大小 {size}")
        if size < 32:  # 设置最大字号限制
            new_size = size + 1
            logger.info(f"zoom_in: 放大到 {new_size}")
            
            # 更新设置中的字体大小
            settings.set("editor_font_size", new_size)
            logger.info(f"zoom_in: 已保存字体大小 {new_size} 到设置")
            
            # 重新应用字体设置，包括CSS样式
            self.apply_font_settings()
        else:
            logger.info(f"zoom_in: 已达到最大字体大小限制 {size}")
    
    def zoom_out(self):
        """缩小字体"""
        font = self.font()
        size = font.pointSize()
        logger.info(f"zoom_out: 当前字体大小 {size}")
        if size > 6:  # 设置最小字号限制
            new_size = size - 1
            logger.info(f"zoom_out: 缩小到 {new_size}")
            
            # 更新设置中的字体大小
            settings.set("editor_font_size", new_size)
            logger.info(f"zoom_out: 已保存字体大小 {new_size} 到设置")
            
            # 重新应用字体设置，包括CSS样式
            self.apply_font_settings()
        else:
            logger.info(f"zoom_out: 已达到最小字体大小限制 {size}")
            
    def lineNumberAreaWidth(self):
        """计算行号区域宽度
        
        Returns:
            行号区域宽度
        """
        digits = 1
        max_num = max(1, self.blockCount())
        while max_num >= 10:
            max_num //= 10
            digits += 1
        
        # 使用行号区域的字体指标
        if hasattr(self, 'line_number_area') and self.line_number_area:
            metrics = QFontMetrics(self.line_number_area.font())
        else:
            metrics = self.fontMetrics()
            
        # 增加额外的左右边距：左边距5px + 数字宽度 + 右边距10px
        space = 15 + metrics.horizontalAdvance('9') * digits
        
        return space
        
    def updateLineNumberAreaWidth(self, newBlockCount):
        """更新行号区域宽度
        
        Args:
            newBlockCount: 新的块数量
        """
        self.setViewportMargins(self.lineNumberAreaWidth(), 0, 0, 0)
        
    def updateLineNumberArea(self, rect, dy):
        """更新行号区域
        
        Args:
            rect: 更新矩形
            dy: 垂直滚动距离
        """
        if dy:
            self.line_number_area.scroll(0, dy)
        else:
            self.line_number_area.update(0, rect.y(), self.line_number_area.width(), rect.height())
            
        if rect.contains(self.viewport().rect()):
            self.updateLineNumberAreaWidth(0)
            
    def resizeEvent(self, event):
        """调整大小事件
        
        Args:
            event: 大小事件
        """
        super().resizeEvent(event)
        
        cr = self.contentsRect()
        self.line_number_area.setGeometry(
            QRect(cr.left(), cr.top(), self.lineNumberAreaWidth(), cr.height())
        )
        
    def lineNumberAreaPaintEvent(self, event):
        """行号区域绘制事件
        
        Args:
            event: 绘制事件
        """
        painter = QPainter(self.line_number_area)
        
        # 使用固定的颜色配置
        bg_color = QColor("#F5F5F5")  # 浅灰色背景
        painter.fillRect(event.rect(), bg_color)
        
        # 设置行号字体
        painter.setFont(self.line_number_area.font())
        
        # 获取行号区域的字体指标
        line_number_metrics = QFontMetrics(self.line_number_area.font())
        
        block = self.firstVisibleBlock()
        block_number = block.blockNumber()
        top = round(self.blockBoundingGeometry(block).translated(self.contentOffset()).top())
        bottom = top + round(self.blockBoundingRect(block).height())
        
        while block.isValid() and top <= event.rect().bottom():
            if block.isVisible() and bottom >= event.rect().top():
                number = str(block_number + 1)
                # 使用浅灰色作为行号颜色
                painter.setPen(QColor("#AAAAAA"))  # 浅灰色
                painter.drawText(
                    5, top, self.line_number_area.width() - 10, 
                    line_number_metrics.height(),
                    Qt.AlignRight, number
                )
                
            block = block.next()
            top = bottom
            bottom = top + round(self.blockBoundingRect(block).height())
            block_number += 1
        
        # 绘制右侧分隔线 - 使用浅灰色
        painter.drawLine(
            self.line_number_area.width() - 1, event.rect().top(),
            self.line_number_area.width() - 1, event.rect().bottom()
        )
    
    def highlightCurrentLine(self):
        """高亮当前行"""
        extraSelections = []
        
        if not self.isReadOnly():
            selection = QTextEdit.ExtraSelection()
            
            # 使用更浅的背景色作为光标所在行的背景色
            current_line_color = QColor("#F5F9FF")  # 非常浅的蓝色
            
            # 应用高亮颜色
            selection.format.setBackground(current_line_color)
            selection.format.setProperty(QTextFormat.FullWidthSelection, True)
            selection.cursor = self.textCursor()
            selection.cursor.clearSelection()
            extraSelections.append(selection)
            
        self.setExtraSelections(extraSelections)
        
    def setAutoIndentation(self, enabled):
        """设置自动缩进
        
        Args:
            enabled: 是否启用
        """
        self._auto_indent = enabled
        
    def _check_sql_syntax(self):
        """检查SQL语法错误"""
        sql_text = self.toPlainText()
        if not sql_text.strip():
            return
            
        # 这里可以添加SQL语法检查逻辑
        # 目前只是一个占位符，因为SQLCodeEditor没有error_highlighter和status_label
        pass
        
    def apply_font_settings(self):
        """应用字体设置"""
        try:
            # 从设置中读取字体配置
            editor_font_family = settings.get("editor_font_family", "Consolas")
            editor_font_size = settings.get("editor_font_size", 12)
            
            logger.info(f"开始应用字体设置: {editor_font_family}, 大小: {editor_font_size}")
            
            # 检查当前字体
            current_font = self.font()
            logger.info(f"应用前字体: {current_font.family()}, 大小: {current_font.pointSize()}")
            
            # 使用样式表方式设置字体（更强制）
            self.update_styles()
            
            # 同时使用传统方式设置字体
            font = QFont(editor_font_family)
            font.setFixedPitch(True)
            font.setPointSize(editor_font_size)
            self.setFont(font)
            
            # 检查最终结果
            final_font = self.font()
            logger.info(f"最终字体: {final_font.family()}, 大小: {final_font.pointSize()}")
            
            # 更新行号区域的字体
            if hasattr(self, 'line_number_area'):
                logger.info("更新行号区域字体...")
                line_number_font = QFont(editor_font_family)
                line_number_font.setFixedPitch(True)
                line_number_font.setPointSize(editor_font_size)
                self.line_number_area.setFont(line_number_font)
                
                # 验证行号区域字体
                actual_line_font = self.line_number_area.font()
                logger.info(f"行号区域字体: {actual_line_font.family()}, 大小: {actual_line_font.pointSize()}")
            
            # 强制刷新编辑器和行号区域
            self.update_tab_width()
            self.updateLineNumberAreaWidth(0)
            if hasattr(self, 'line_number_area'):
                self.line_number_area.update()
            self.update()
            
            logger.info(f"已应用字体设置: {editor_font_family}, 大小: {editor_font_size}")
            
        except Exception as e:
            logger.error(f"应用字体设置失败: {e}")
            import traceback
            traceback.print_exc()


class SQLEditorTab(QWidget):
    """SQL编辑器标签页"""
    
    # 信号定义
    query_executed = Signal(str, QueryResult)  # 查询ID，查询结果
    status_changed = Signal(str)  # 状态变化信号
    cursor_position_changed = Signal(int, int)  # 光标位置变化信号（行号，列号）
    
    def __init__(self, parent=None, title="新建查询"):
        """初始化编辑器标签页
        
        Args:
            parent: 父部件
            title: 标签页标题
        """
        super().__init__(parent)
        self.setObjectName("SQLEditorTab")
        self.title = title
        
        # 查询管理器
        self.query_manager = get_query_manager()
        
        # 当前查询ID
        self.current_query_id = None
        
        # 错误高亮器
        self.error_highlighter = None
        
        # 语法检查定时器

        self.syntax_check_timer = QTimer(self)
        self.syntax_check_timer.setSingleShot(True)
        self.syntax_check_timer.timeout.connect(self._check_sql_syntax)
        
        # 初始化UI
        self._init_ui()
        
        # SQL补全器
        self.completer = SQLCompleter(self.editor)
        
        # 已分离的结果窗口字典
        self.detached_windows = {}
        
        # 设置连接
        self._setup_connections()
        
        # 设置焦点到编辑器
        self.editor.setFocus()
        
        # 安装事件过滤器
        self.editor.installEventFilter(self)
        
        # 发出初始状态信号
        self.status_changed.emit(tr("sql_status_ready", "就绪"))
        self.cursor_position_changed.emit(1, 1)
        
    def _init_ui(self):
        """初始化用户界面"""
        # 创建布局
        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        
        # 确保错误高亮器已初始化
        if not hasattr(self, 'error_highlighter') or self.error_highlighter is None:
            # 稍后会在editor创建后初始化
            self.error_highlighter = None
        
        # 设置通用提示信息
        self.setToolTip("F5 或 Ctrl+Enter 执行查询；如果有选中的SQL，则只执行选中部分；否则执行全部SQL")
        
        # 创建工具栏
        toolbar = QToolBar()
        toolbar.setIconSize(QSize(20, 20))
        toolbar.setMovable(False)
        toolbar.setToolButtonStyle(Qt.ToolButtonIconOnly)
        
        # 添加执行按钮
        self.run_btn = QAction(get_icon("play"), "执行查询", self)
        self.run_btn.setShortcut("F5")
        self.run_btn.setToolTip("执行查询 (F5 或 Ctrl+Enter)\n如果有选中的SQL，则只执行选中部分；否则执行全部SQL")
        self.run_btn.triggered.connect(self.execute_query)
        toolbar.addAction(self.run_btn)
        
        # 添加取消按钮
        self.cancel_btn = QAction(get_icon("stop"), "取消查询", self)
        self.cancel_btn.setShortcut("Esc")
        self.cancel_btn.triggered.connect(self.cancel_query)
        self.cancel_btn.setEnabled(False)
        toolbar.addAction(self.cancel_btn)
        
        # 添加分隔符
        toolbar.addSeparator()
        
        # 添加格式化按钮
        self.format_btn = QAction(get_icon("format"), "格式化SQL", self)
        self.format_btn.setShortcut("Ctrl+Shift+F")
        self.format_btn.triggered.connect(self.format_sql)
        toolbar.addAction(self.format_btn)
        
        # 添加清空按钮
        # self.clear_btn = QAction(get_icon("refresh"), "清空编辑器", self)
        # self.clear_btn.triggered.connect(self.clear_editor)
        # toolbar.addAction(self.clear_btn)
        
        # 添加查找按钮
        # self.find_btn = QAction(get_icon("search"), "查找", self)
        # self.find_btn.setShortcut("Ctrl+F")
        # self.find_btn.triggered.connect(self._show_find_dialog)
        # toolbar.addAction(self.find_btn)
        
        # 添加注释按钮
        self.comment_btn = QAction(get_icon("code"), "注释代码", self)
        self.comment_btn.setShortcut("Ctrl+/")
        self.comment_btn.triggered.connect(self._toggle_comment)
        toolbar.addAction(self.comment_btn)
        
        # 添加分隔符
        toolbar.addSeparator()
        
        # 添加代码折叠按钮
        # self.fold_btn = QAction(get_icon("chevron-right"), "折叠/展开代码块", self)
        # self.fold_btn.setShortcut("Ctrl+Shift+[")
        # self.fold_btn.triggered.connect(self._toggle_fold)
        # toolbar.addAction(self.fold_btn)
        
        # 添加自动缩进按钮
        # self.indent_btn = QAction(get_icon("code"), "自动缩进", self)
        # self.indent_btn.setShortcut("Ctrl+I")
        # self.indent_btn.triggered.connect(self._auto_indent)
        # toolbar.addAction(self.indent_btn)
        
        # 添加代码片段按钮
        self.snippet_btn = QAction(get_icon("file-text"), "插入代码片段", self)
        self.snippet_btn.triggered.connect(self._show_snippets)
        toolbar.addAction(self.snippet_btn)
        
        # 添加到布局
        layout.addWidget(toolbar)
        
        # 创建编辑器
        self.editor = SQLCodeEditor(self)
        self.editor.setLineWrapMode(QPlainTextEdit.NoWrap)
        
        # 进度条
        self.progress_bar = QProgressBar()
        self.progress_bar.setFixedHeight(5)
        self.progress_bar.setTextVisible(False)
        self.progress_bar.setVisible(False)
        
        # 创建查找面板（默认隐藏）
        self.find_panel = self._create_find_panel()
        self.find_panel.setVisible(False)
        
        # 添加到布局
        layout.addWidget(self.editor, 1)
        layout.addWidget(self.find_panel)
        layout.addWidget(self.progress_bar)
        
        # 设置布局
        self.setLayout(layout)
        
    def _setup_connections(self):
        """设置信号连接"""
        # 查询管理器信号
        self.query_manager.query_started.connect(self._on_query_started)
        self.query_manager.query_completed.connect(self._on_query_completed)
        self.query_manager.query_error.connect(self._on_query_error)
        self.query_manager.query_timeout.connect(self._on_query_timeout)
        
        # 编辑器信号
        self.editor.cursorPositionChanged.connect(self._update_cursor_position)
        
        # 初始化错误高亮器
        if not hasattr(self, 'error_highlighter') or self.error_highlighter is None:
            from ui.widgets.sql_highlighter import SQLErrorHighlighter
            self.error_highlighter = SQLErrorHighlighter(self.editor.document())
        
        # 初始化并更新自动补全的元数据
        if hasattr(self, 'completer') and self.completer:
            self.completer.update_metadata()
            
        # 添加自定义快捷键
        self.editor.installEventFilter(self)
        
    def _create_find_panel(self):
        """创建查找替换面板
        
        Returns:
            查找替换面板
        """
        panel = QFrame()
        panel.setFrameShape(QFrame.StyledPanel)
        panel.setObjectName("find_panel")
        
        layout = QHBoxLayout(panel)
        layout.setContentsMargins(5, 5, 5, 5)
        
        # 暂时使用一个标签占位
        layout.addWidget(QLabel("查找/替换 (将在后续实现)"))
        
        # 关闭按钮
        close_btn = QPushButton()
        close_btn.setIcon(get_icon("close"))
        close_btn.setFixedSize(24, 24)
        close_btn.clicked.connect(lambda: panel.setVisible(False))
        layout.addWidget(close_btn)
        
        return panel
        
    def _show_find_dialog(self):
        """显示查找对话框"""
        self.find_panel.setVisible(True)
        
    def _update_cursor_position(self):
        """更新光标位置并发出信号"""
        cursor = self.editor.textCursor()
        line = cursor.blockNumber() + 1
        column = cursor.columnNumber() + 1
        # 发出光标位置变化信号
        self.cursor_position_changed.emit(line, column)
        
    def execute_query(self):
        """执行SQL查询
        
        如果有选中文本，则执行选中的SQL；否则执行整个编辑器中的SQL
        """
        # 获取编辑器中的SQL
        cursor = self.editor.textCursor()
        if cursor.hasSelection():
            # 如果有选中文本，则执行选中的SQL
            sql = cursor.selectedText().strip()
            self.status_changed.emit(tr("sql_status_executing_selected", "正在执行选中的SQL..."))
        else:
            # 否则执行整个编辑器中的SQL
            sql = self.editor.toPlainText().strip()
        
        if not sql:
            self.status_changed.emit(tr("sql_status_no_sql", "没有SQL语句可执行"))
            return
            
        # 确保错误高亮器已初始化
        if not hasattr(self, 'error_highlighter') or self.error_highlighter is None:
            # 如果错误高亮器尚未初始化，则初始化它
            from ui.widgets.sql_highlighter import SQLErrorHighlighter
            self.error_highlighter = SQLErrorHighlighter(self.editor.document())
        
        # 清除错误高亮
        self.error_highlighter.clear_errors()
        
        # 执行查询
        self.current_query_id = self.query_manager.execute_query(sql)
        
        # 更新UI状态
        self.run_btn.setEnabled(False)
        self.cancel_btn.setEnabled(True)
        self.progress_bar.setVisible(True)
        self.progress_bar.setValue(0)
        self.status_changed.emit(tr("sql_status_executing", "正在执行查询..."))
        
    def cancel_query(self):
        """取消当前查询"""
        if self.current_query_id and self.query_manager.is_query_running(self.current_query_id):
            self.query_manager.cancel_query(self.current_query_id)
            self.status_changed.emit(tr("sql_status_cancelled", "查询已取消"))
            
        # 重置UI状态
        self.run_btn.setEnabled(True)
        self.cancel_btn.setEnabled(False)
        self.progress_bar.setVisible(False)
        
    def format_sql(self):
        """格式化SQL查询"""
        # 获取当前文本
        current_text = self.editor.toPlainText()
        if not current_text.strip():
            return
            
        # 获取当前光标位置
        cursor = self.editor.textCursor()
        current_position = cursor.position()
        
        try:
            # 尝试使用sqlparse格式化SQL
            try:
                import sqlparse
                formatted_sql = sqlparse.format(
                    current_text,
                    keyword_case='upper',
                    identifier_case='lower',
                    reindent=True,
                    indent_width=4,
                    wrap_after=80,
                    comma_first=False
                )
            except ImportError:
                # 如果没有sqlparse，使用简单的格式化方法
                formatted_sql = self._simple_format_sql(current_text)
        
            # 使用格式化后的SQL替换编辑器内容
            cursor.beginEditBlock()
            cursor.select(QTextCursor.Document)
            cursor.removeSelectedText()
            cursor.insertText(formatted_sql)
            cursor.endEditBlock()
            
            # 尝试恢复光标位置
            if current_position <= len(formatted_sql):
                cursor.setPosition(current_position)
                self.editor.setTextCursor(cursor)
                
            self.status_changed.emit(tr("sql_status_formatted", "SQL已格式化"))
            
        except Exception as e:
            logger.error(f"格式化SQL时出错: {str(e)}")
            self.status_changed.emit(f"{tr('sql_status_format_failed', '格式化失败')}: {str(e)}")
            
    def _simple_format_sql(self, sql: str) -> str:
        """简单的SQL格式化方法
        
        Args:
            sql: 原始SQL文本
            
        Returns:
            格式化后的SQL
        """
        # 主要关键字列表
        major_keywords = [
            "SELECT", "FROM", "WHERE", "GROUP BY", "ORDER BY",
            "HAVING", "LIMIT", "OFFSET", "JOIN", "INNER JOIN",
            "LEFT JOIN", "RIGHT JOIN", "FULL JOIN", "CROSS JOIN",
            "INSERT INTO", "VALUES", "UPDATE", "SET", "DELETE FROM",
            "CREATE TABLE", "ALTER TABLE", "DROP TABLE", "WITH"
        ]
        
        # 子条件关键字
        sub_keywords = [
            "AND", "OR", "UNION", "UNION ALL", "EXCEPT", "INTERSECT"
        ]
        
        # 转换为大写关键字
        sql = re.sub(r'\b(SELECT|FROM|WHERE|GROUP\s+BY|ORDER\s+BY|HAVING|LIMIT|OFFSET|JOIN|UNION|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP|SET|VALUES|CASE|WHEN|THEN|ELSE|END|AS)\b',
                     lambda m: m.group(1).upper(), sql, flags=re.IGNORECASE)
        
        # 添加换行和缩进
        lines = []
        indent_level = 0
        in_parentheses = 0
        current_line = ""
        
        # 分割SQL（保留分隔符）
        tokens = re.findall(r'[\w\.]+|\S', sql)
        i = 0
        while i < len(tokens):
            token = tokens[i]
            upper_token = token.upper()
            
            # 处理括号
            if token == "(":
                in_parentheses += 1
                current_line += token
            elif token == ")":
                in_parentheses -= 1
                current_line += token
            # 处理主要关键字
            elif in_parentheses == 0 and upper_token in major_keywords:
                if current_line.strip():
                    lines.append(" " * (4 * indent_level) + current_line.strip())
                current_line = upper_token
                if upper_token in ["SELECT", "INSERT", "UPDATE", "DELETE", "CREATE", "WITH"]:
                    indent_level = 0
                elif upper_token in ["FROM", "WHERE", "JOIN", "INNER JOIN", "LEFT JOIN", "RIGHT JOIN"]:
                    indent_level = 1
            # 处理子条件关键字
            elif in_parentheses == 0 and upper_token in sub_keywords:
                if current_line.strip():
                    lines.append(" " * (4 * indent_level) + current_line.strip())
                current_line = " " * (4 * indent_level) + upper_token
            # 处理逗号
            elif token == ",":
                current_line += token
                if in_parentheses == 0:
                    if current_line.strip():
                        lines.append(" " * (4 * indent_level) + current_line.strip())
                    current_line = ""
            # 其他标记
            else:
                current_line += " " + token if current_line and not current_line.endswith(" ") else token
            
            i += 1
        
        # 添加最后一行
        if current_line.strip():
            lines.append(" " * (4 * indent_level) + current_line.strip())
        
        return "\n".join(lines)

    def _toggle_comment(self):
        """切换SQL注释（注释/取消注释当前行或选中内容）"""
        cursor = self.editor.textCursor()
        
        # 检查是否有选择
        has_selection = cursor.hasSelection()
        start_block = self.editor.document().findBlock(cursor.selectionStart())
        end_block = self.editor.document().findBlock(cursor.selectionEnd())
        
        # 记录选择范围
        selection_start = cursor.selectionStart()
        selection_end = cursor.selectionEnd()
        
        # 开始编辑操作
        cursor.beginEditBlock()
        
        # 遍历所有选中的块
        current_block = start_block
        is_commenting = True  # 默认执行注释操作
        
        # 首先检查是否所有行都已注释，如果是则执行取消注释操作
        check_block = start_block
        all_commented = True
        while check_block != end_block.next():
            line_text = check_block.text().lstrip()
            if not line_text.startswith('--'):
                all_commented = False
                break
            check_block = check_block.next()
        
        is_commenting = not all_commented
        
        # 执行注释或取消注释
        current_block = start_block
        while current_block != end_block.next():
            line_text = current_block.text()
            cursor.setPosition(current_block.position())
            
            if is_commenting:
                # 添加注释
                cursor.setPosition(current_block.position())
                cursor.movePosition(QTextCursor.StartOfBlock)
                cursor.insertText('-- ')
            else:
                # 移除注释
                if line_text.lstrip().startswith('--'):
                    cursor.setPosition(current_block.position())
                    cursor.movePosition(QTextCursor.StartOfBlock)
                    cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, 
                                      line_text.find('--') + 2)
                    cursor.removeSelectedText()
            
            current_block = current_block.next()
        
        # 结束编辑操作
        cursor.endEditBlock()
        
        # 恢复选择
        if has_selection:
            # 重新计算选择范围，因为添加/移除注释会改变位置
            new_cursor = self.editor.textCursor()
            if is_commenting:
                # 注释添加了字符，所以选区扩大
                new_selection_end = selection_end + (end_block.blockNumber() - 
                                                    start_block.blockNumber() + 1) * 3
                new_cursor.setPosition(selection_start)
                new_cursor.setPosition(new_selection_end, QTextCursor.KeepAnchor)
            else:
                # 注释被移除，选区缩小
                commented_lines = 0
                check_block = start_block
                while check_block != end_block.next():
                    if check_block.text().lstrip().startswith('--'):
                        commented_lines += 1
                    check_block = check_block.next()
                
                new_selection_end = selection_end - commented_lines * 3
                new_cursor.setPosition(selection_start)
                new_cursor.setPosition(new_selection_end, QTextCursor.KeepAnchor)
                
            self.editor.setTextCursor(new_cursor)

    def _toggle_fold(self):
        """折叠/展开代码块"""
        cursor = self.editor.textCursor()
        block = cursor.block()
        if not block.isValid():
            return
            
        # 检查是否可以折叠当前块
        text = block.text().strip().upper()
        # 检查是否是可折叠的SQL子句开始
        if (text.startswith("SELECT") or text.startswith("WITH") or 
            text.startswith("INSERT") or text.startswith("UPDATE") or 
            text.startswith("DELETE") or text.startswith("CREATE")):
            
            # 查找对应的结束位置 - 对于SQL可以是分号或空行
            start_block = block
            end_block = block
            found_end = False
            
            # 向下搜索直到找到分号或空行
            current_block = block.next()
            while current_block.isValid() and not found_end:
                if (current_block.text().strip().endswith(";") or 
                    not current_block.text().strip()):
                    end_block = current_block
                    found_end = True
                current_block = current_block.next()
            
            if not found_end:
                # 如果没有找到明确的结束，使用最后一个有效块
                end_block = self.editor.document().lastBlock()
            
            # 检查是否已折叠
            block_data = start_block.userData()
            is_folded = block_data and hasattr(block_data, 'folded') and block_data.folded
            
            # 执行折叠或展开
            if is_folded:
                # 展开已折叠代码
                self._unfold_code(start_block, end_block)
            else:
                # 折叠代码
                self._fold_code(start_block, end_block)
                
            # 更新编辑器视图
            self.editor.update()

    def _fold_code(self, start_block, end_block):
        """折叠代码块
        
        Args:
            start_block: 开始块
            end_block: 结束块
        """
        # 设置起始块的折叠标志
        block_data = start_block.userData()
        if not block_data or not isinstance(block_data, SQLBlockData):
            block_data = SQLBlockData()
        block_data.folded = True
        self.editor.document().markContentsDirty(start_block.position(), 1)
        start_block.setUserData(block_data)
        
        # 隐藏中间块
        current_block = start_block.next()
        while current_block.isValid() and current_block != end_block.next():
            current_block.setVisible(False)
            current_block = current_block.next()
        
        # 更新文档布局
        self.editor.document().markContentsDirty(
            start_block.position(),
            end_block.position() + end_block.length() - start_block.position()
        )
        
    def _unfold_code(self, start_block, end_block):
        """展开代码块
        
        Args:
            start_block: 开始块
            end_block: 结束块
        """
        # 清除起始块的折叠标志
        block_data = start_block.userData()
        if block_data and isinstance(block_data, SQLBlockData):
            block_data.folded = False
            start_block.setUserData(block_data)
        
        # 显示中间块
        current_block = start_block.next()
        while current_block.isValid() and current_block != end_block.next():
            current_block.setVisible(True)
            current_block = current_block.next()
        
        # 更新文档布局
        self.editor.document().markContentsDirty(
            start_block.position(),
            end_block.position() + end_block.length() - start_block.position()
        )

    def _auto_indent(self):
        """自动缩进SQL代码"""
        cursor = self.editor.textCursor()
        
        # 如果有选区，只处理选中部分
        if cursor.hasSelection():
            start_pos = cursor.selectionStart()
            end_pos = cursor.selectionEnd()
            start_block = self.editor.document().findBlock(start_pos)
            end_block = self.editor.document().findBlock(end_pos)
        else:
            # 否则处理整个文档
            start_block = self.editor.document().firstBlock()
            end_block = self.editor.document().lastBlock()
        
        # 开始编辑操作
        cursor.beginEditBlock()
        
        # 设置初始缩进级别
        indent_level = 0
        in_parentheses_level = 0
        
        # 遍历所有块
        current_block = start_block
        while current_block.isValid() and current_block.blockNumber() <= end_block.blockNumber():
            text = current_block.text().strip()
            
            # 跳过空行和注释行
            if not text or text.startswith('--'):
                current_block = current_block.next()
                continue
            
            # 检查括号变化
            in_parentheses_level += text.count('(') - text.count(')')
            
            # 调整缩进级别
            if any(kw in text.upper() for kw in ["SELECT", "INSERT", "UPDATE", "DELETE", "CREATE", "WITH"]):
                # 主要语句开始，重置缩进
                if current_block == start_block:
                    indent_level = 0
                else:
                    # 如果不是第一块，可能是子查询，增加缩进
                    indent_level += 1
            
            # FROM, WHERE等子句增加缩进
            if any(kw in text.upper() for kw in ["FROM", "WHERE", "GROUP BY", "ORDER BY", "HAVING"]):
                if indent_level == 0:
                    indent_level = 1
            
            # JOIN子句也增加缩进
            if any(kw in text.upper() for kw in ["JOIN", "LEFT JOIN", "RIGHT JOIN", "INNER JOIN"]):
                if indent_level < 1:
                    indent_level = 1
            
            # 分号表示语句结束，减少缩进
            if text.endswith(';'):
                if in_parentheses_level == 0:
                    indent_level = max(0, indent_level - 1)
            
            # 应用缩进
            cursor.setPosition(current_block.position())
            cursor.movePosition(QTextCursor.StartOfLine)
            
            # 移除现有前导空格
            spaces_to_remove = len(current_block.text()) - len(current_block.text().lstrip())
            if spaces_to_remove > 0:
                cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, spaces_to_remove)
                cursor.removeSelectedText()
            
            # 添加正确的缩进
            cursor.insertText(' ' * (4 * indent_level))
            
            current_block = current_block.next()
        
        # 结束编辑操作
        cursor.endEditBlock()

    def _show_snippets(self):
        """显示代码片段菜单"""
        # 创建菜单
        menu = QMenu(self)
        
        # 添加常用SQL片段
        snippets = [
            ("基本SELECT", "SELECT * FROM "),
            ("带条件SELECT", "SELECT * FROM table_name WHERE condition"),
            ("JOIN查询", "SELECT t1.*, t2.* FROM table1 t1 JOIN table2 t2 ON t1.id = t2.id"),
            ("分组查询", "SELECT column1, COUNT(*) FROM table_name GROUP BY column1"),
            ("排序查询", "SELECT * FROM table_name ORDER BY column1 DESC"),
            ("限制结果", "SELECT * FROM table_name LIMIT 10"),
            ("创建表", "CREATE TABLE table_name (column1 type1, column2 type2)"),
            ("插入数据", "INSERT INTO table_name (column1, column2) VALUES (value1, value2)"),
            ("更新数据", "UPDATE table_name SET column1 = value1 WHERE condition"),
            ("删除数据", "DELETE FROM table_name WHERE condition"),
            ("子查询", "SELECT * FROM table_name WHERE column1 IN (SELECT column1 FROM other_table)")
        ]
        
        # 添加到菜单
        for name, sql in snippets:
            action = menu.addAction(name)
            action.setData(sql)
            action.triggered.connect(lambda checked, sql=sql: self._insert_snippet(sql))
        
        # 显示菜单
        menu.exec_(QCursor.pos())
    
    def _insert_snippet(self, snippet: str):
        """插入代码片段
        
        Args:
            snippet: 要插入的代码片段
        """
        cursor = self.editor.textCursor()
        cursor.insertText(snippet)
        self.editor.setFocus()
        
    def _check_sql_syntax(self):
        """检查SQL语法错误"""
        sql_text = self.toPlainText()
        if not sql_text.strip():
            return
            
        # 这里可以添加SQL语法检查逻辑
        # 目前只是一个占位符，因为SQLCodeEditor没有error_highlighter和status_label
        pass

    def _on_text_changed(self):
        """文本变化时的处理"""
        # 延迟检查语法，避免频繁检查
        self.syntax_check_timer.start(1000)  # 1秒后检查语法
        
        # 更新光标位置
        self._update_cursor_position()
        
    def _on_query_started(self, query_id: str):
        """查询开始处理
        
        Args:
            query_id: 查询ID
        """
        if query_id != self.current_query_id:
            return
            
        logger.info(f"查询开始: {query_id}")
        
    def _on_query_completed(self, result: QueryResult):
        """查询完成处理
        
        Args:
            result: 查询结果
        """
        if result.query_id != self.current_query_id:
            return
            
        logger.info(f"查询完成: {result.query_id}, 成功: {result.success}")
        
        # 更新UI状态
        self.run_btn.setEnabled(True)
        self.cancel_btn.setEnabled(False)
        self.progress_bar.setVisible(False)
        
        # 获取查询文本
        query_sql = None
        if hasattr(result, 'query_text'):
            query_sql = result.query_text
            
        if result.success:
            # 更新状态标签显示查询结果信息
            self.status_changed.emit(
                tr("sql_status_completed", "查询完成，耗时 {0:.2f} 秒，返回 {1} 行数据").format(result.duration, result.row_count)
            )
        else:
            # 显示错误
            self.status_changed.emit(f"{tr('sql_status_failed', '查询失败')}: {result.error}")
            
            # 标记错误位置（简单实现）
            cursor = self.editor.textCursor()
            cursor.movePosition(QTextCursor.Start)
            
            # 确保错误高亮器已初始化
            if not hasattr(self, 'error_highlighter') or self.error_highlighter is None:
                # 如果错误高亮器尚未初始化，则初始化它
                from ui.widgets.sql_highlighter import SQLErrorHighlighter
                self.error_highlighter = SQLErrorHighlighter(self.editor.document())
                
            self.error_highlighter.mark_error(0, len(self.editor.toPlainText()))
            
        # 更新所有分离窗口
        if result.success and hasattr(self, 'detached_windows') and self.detached_windows:
            for window_id, window in self.detached_windows.items():
                try:
                    window.display_result(
                        result.data,
                        query_sql=query_sql,
                        execution_time=result.duration
                    )
                except Exception as e:
                    logger.error(f"更新分离窗口失败: {str(e)}")
        
        # 发出信号 - 这会将结果发送到ResultsDock
        self.query_executed.emit(result.query_id, result)
        
    def _on_query_error(self, query_id: str, error: str):
        """查询错误处理
        
        Args:
            query_id: 查询ID
            error: 错误消息
        """
        if query_id != self.current_query_id:
            return
            
        logger.error(f"查询错误: {query_id}, 错误: {error}")
        
        # 更新UI状态
        self.run_btn.setEnabled(True)
        self.cancel_btn.setEnabled(False)
        self.progress_bar.setVisible(False)
        self.status_changed.emit(f"{tr('sql_status_error', '查询错误')}: {error}")
        
    def _on_query_timeout(self, query_id: str):
        """查询超时处理
        
        Args:
            query_id: 查询ID
        """
        if query_id != self.current_query_id:
            return
            
        logger.warning(f"查询超时: {query_id}")
        
        # 更新UI状态
        self.run_btn.setEnabled(True)
        self.cancel_btn.setEnabled(False)
        self.progress_bar.setVisible(False)
        self.status_changed.emit(tr("sql_status_timeout", "查询超时"))

    def eventFilter(self, obj, event):
        """事件过滤器
        
        Args:
            obj: 触发事件的对象
            event: 事件对象
            
        Returns:
            是否处理了事件
        """
        # 处理特定快捷键
        if obj == self.editor and isinstance(event, QKeyEvent):
            # 首先让补全器处理键盘事件
            if hasattr(self, 'completer') and self.completer and event.type() == QKeyEvent.KeyPress:
                if self.completer.handle_key_press(event):
                    return True
            
            # 处理F5执行查询
            if event.key() == Qt.Key_F5:
                self.execute_query()
                return True
            
            # 处理Ctrl+Enter执行查询
            if event.key() == Qt.Key_Return and event.modifiers() == Qt.ControlModifier:
                self.execute_query()
                return True
            
            # 处理Ctrl+Enter（小键盘Enter键）
            if event.key() == Qt.Key_Enter and event.modifiers() == Qt.ControlModifier:
                self.execute_query()
                return True
                
            # 处理Ctrl+/ 注释或取消注释当前行
            if event.key() == Qt.Key_Slash and event.modifiers() == Qt.ControlModifier:
                self._toggle_comment()
                return True
                
        # 让其他事件继续传递
        return super().eventFilter(obj, event)
        
    def clear_editor(self):
        """清空编辑器"""
        reply = QMessageBox.question(
            self, 
            "确认清空", 
            "确定要清空编辑器内容吗？", 
            QMessageBox.Yes | QMessageBox.No
        )
        
        if reply == QMessageBox.Yes:
            self.editor.clear()
            self.status_changed.emit(tr("sql_status_cleared", "编辑器已清空"))
            
    def set_query_text(self, text: str):
        """设置查询文本
        
        Args:
            text: 查询文本
        """
        self.editor.setPlainText(text)
        
    def append_query_text(self, text: str):
        """添加查询文本
        
        Args:
            text: 查询文本
        """
        cursor = self.editor.textCursor()
        cursor.movePosition(QTextCursor.End)
        cursor.insertText(text)
        self.editor.setTextCursor(cursor)

    def cleanup(self):
        """清理资源"""
        # 取消当前查询
        if self.current_query_id:
            self.cancel_query()
        
        # 断开信号连接
        try:
            self.query_manager.query_started.disconnect()
            self.query_manager.query_completed.disconnect()
            self.query_manager.query_error.disconnect()
            self.query_manager.query_timeout.disconnect()
        except RuntimeError:
            # 信号已经断开
            pass
        
        # 清理编辑器
        if hasattr(self, 'editor'):
            self.editor.cleanup() if hasattr(self.editor, 'cleanup') else None
        
        # 清理补全器
        if hasattr(self, 'completer'):
            self.completer.cleanup()
        
        # 关闭分离的结果窗口
        for window_id, window in list(self.detached_windows.items()):
            try:
                window.close()
            except RuntimeError:
                # 窗口已经关闭
                pass
        self.detached_windows.clear()
        
        logger.info(f"编辑器标签页 '{self.title}' 已清理")
        
    def apply_font_settings(self):
        """应用字体设置到编辑器"""
        if hasattr(self, 'editor') and self.editor:
            self.editor.apply_font_settings()


class SQLEditorWidget(QWidget):
    """SQL编辑器组件类，支持多标签页"""
    
    # 信号定义
    tab_added = Signal(object)  # 新标签页添加信号
    
    def __init__(self, parent=None):
        """初始化SQL编辑器组件
        
        Args:
            parent: 父窗口
        """
        super().__init__(parent)
        self._init_ui()
        
    def _init_ui(self):
        """初始化UI"""
        # 主布局
        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        
        # 标签页控件
        self.tab_widget = QTabWidget()
        self.tab_widget.setTabsClosable(True)
        self.tab_widget.setMovable(True)
        self.tab_widget.setDocumentMode(True)
        self.tab_widget.tabCloseRequested.connect(self._close_tab)
        
        # 标签右键菜单
        self.tab_widget.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tab_widget.customContextMenuRequested.connect(self._show_tab_context_menu)
        
        # 添加标签页按钮
        self.tab_widget.setCornerWidget(self._create_corner_widget())
        
        layout.addWidget(self.tab_widget)
        
        # 创建初始标签页
        self.add_tab()
        
    def _create_corner_widget(self) -> QWidget:
        """创建标签页角落的控件
        
        Returns:
            角落控件
        """
        widget = QWidget()
        layout = QHBoxLayout(widget)
        layout.setContentsMargins(0, 0, 0, 0)
        
        # 添加标签页按钮
        add_button = QToolButton()
        add_button.setText("+")
        add_button.setToolTip(tr("editor_new_query", "新建查询"))
        add_button.clicked.connect(lambda: self.add_tab())
        
        layout.addWidget(add_button)
        return widget
        
    def add_tab(self, title: str = None) -> SQLEditorTab:
        """添加新标签页
        
        Args:
            title: 标签标题
            
        Returns:
            新建的标签页
        """
        if title is None:
            title = tr("editor_new_query", "新建查询")
            
        # 创建标签页
        tab = SQLEditorTab(self, title)
        
        # 添加到标签页控件
        index = self.tab_widget.addTab(tab, title)
        self.tab_widget.setCurrentIndex(index)
        
        # 发出新标签页添加信号
        self.tab_added.emit(tab)
        
        return tab
        
    def _close_tab(self, index: int):
        """关闭标签页
        
        Args:
            index: 标签页索引
        """
        # 如果只有一个标签页，先创建新标签页再关闭
        if self.tab_widget.count() == 1:
            self.add_tab()
            
        # 获取标签页
        tab = self.tab_widget.widget(index)
        
        # 关闭标签页
        self.tab_widget.removeTab(index)
        
        # 销毁标签页
        if tab:
            tab.deleteLater()
            
    def _show_tab_context_menu(self, pos):
        """显示标签右键菜单
        
        Args:
            pos: 位置
        """
        index = self.tab_widget.tabBar().tabAt(pos)
        if index < 0:
            return
            
        menu = QMenu(self)
        
        # 关闭当前标签
        close_action = menu.addAction(tr("editor_close_tab", "关闭"))
        close_action.triggered.connect(lambda: self._close_tab(index))
        
        # 关闭其他标签
        close_others_action = menu.addAction(tr("editor_close_others", "关闭其他标签"))
        close_others_action.triggered.connect(lambda: self._close_other_tabs(index))
        
        # 关闭所有标签
        close_all_action = menu.addAction(tr("editor_close_all", "关闭所有标签"))
        close_all_action.triggered.connect(self._close_all_tabs)
        
        menu.exec_(self.tab_widget.tabBar().mapToGlobal(pos))
        
    def _close_other_tabs(self, keep_index: int):
        """关闭其他标签页
        
        Args:
            keep_index: 保留的标签页索引
        """
        # 从后往前关闭
        for i in range(self.tab_widget.count() - 1, -1, -1):
            if i != keep_index:
                tab = self.tab_widget.widget(i)
                self.tab_widget.removeTab(i)
                if tab:
                    tab.deleteLater()
                    
    def _close_all_tabs(self):
        """关闭所有标签页"""
        self._close_other_tabs(-1)  # 关闭所有标签
        self.add_tab()  # 添加一个新标签
            
    def current_tab(self) -> Optional[SQLEditorTab]:
        """获取当前标签页
        
        Returns:
            当前标签页或None
        """
        index = self.tab_widget.currentIndex()
        if index >= 0:
            return self.tab_widget.widget(index)
        return None
        
    def execute_sql(self, sql: str):
        """在当前标签页执行SQL
        
        Args:
            sql: SQL语句
        """
        tab = self.current_tab()
        if tab:
            tab.set_query_text(sql)
            tab.execute_query()
            
    def insert_sql(self, sql: str):
        """在当前标签页插入SQL
        
        Args:
            sql: SQL语句
        """
        tab = self.current_tab()
        if tab:
            current_text = tab.editor.toPlainText()
            if current_text and not current_text.endswith('\n'):
                sql = '\n' + sql
            tab.append_query_text(sql)

    def cleanup(self):
        """清理资源"""
        try:
            # 关闭所有标签页，确保资源释放
            for i in range(self.tab_widget.count()):
                tab = self.tab_widget.widget(i)
                if tab and hasattr(tab, 'cleanup'):
                    tab.cleanup()
        except Exception as e:
            logger.error(f"清理SQL编辑器资源时出错: {str(e)}")
    
    def apply_font_settings(self):
        """应用字体设置到所有标签页"""
        try:
            # 应用字体设置到所有标签页
            for i in range(self.tab_widget.count()):
                tab = self.tab_widget.widget(i)
                if tab and hasattr(tab, 'apply_font_settings'):
                    tab.apply_font_settings()
            logger.info("已应用字体设置到所有编辑器标签页")
        except Exception as e:
            logger.error(f"应用字体设置失败: {e}")
